-
Notifications
You must be signed in to change notification settings - Fork 7.9k
ext/bcmath: Simplify bc_divide()
code
#17987
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
ead66ef
to
6f044c5
Compare
6f044c5
to
d016743
Compare
…early return cases
ext/bcmath/libbcmath/src/div.c
Outdated
bc_free_num(quot); | ||
goto quot_zero; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if I should leave this as is...
Fixed.
61d632e
to
8ea5dd6
Compare
Can you ping when this is actually ready? Since requesting a review there have been various pushes to the PR so it's unclear when this is ready. |
@nielsdos |
Ready for review🙏 |
Ok first two commits are obviously fine already, now taking a look at the refactoring itself. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comments (so far).
Did you do any advanced testing like differential fuzzing? We had quite a few bugs in bcmath in early 8.4 releases that could've been caught via differential fuzzing
ext/bcmath/libbcmath/src/convert.h
Outdated
size_t tmp_len = MIN(BC_VECTOR_SIZE - zeros, nlen); | ||
for (size_t i = 0; i < tmp_len; i++) { | ||
*n_vector += *nend * base; | ||
base *= BASE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having both base
and BASE
is confusing. Please rename the base
variable to something more meaningful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to check: this multiplication can't overflow because the highest it can ever get is BC_POW_10_LUT[BC_VECTOR_SIZE]
right? (i.e. this function essentially pads zeros to the left side)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in 1c9199d
Just to check: this multiplication can't overflow because the highest it can ever get is
BC_POW_10_LUT[BC_VECTOR_SIZE]
right? (i.e. this function essentially pads zeros to the left side)
Yes, that's right.
ext/bcmath/libbcmath/src/convert.h
Outdated
if (zeros > 0) { | ||
*n_vector = 0; | ||
BC_VECTOR base = BC_POW_10_LUT[zeros]; | ||
size_t tmp_len = MIN(BC_VECTOR_SIZE - zeros, nlen); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please pick a more meaningful variable name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in 1c9199d
ext/bcmath/libbcmath/src/div.c
Outdated
{ | ||
char *qptr = (*quot)->n_value; | ||
if (quot_size <= quot_scale) { | ||
/* int is 0 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this comment mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your simpler code makes this comment unnecessary, but just to be clear:
This meant "the integer part is 0".
ext/bcmath/libbcmath/src/div.c
Outdated
_bc_rm_leading_zeros(*quot); | ||
if (bc_is_zero(*quot)) { | ||
(*quot)->n_sign = PLUS; | ||
(*quot)->n_scale = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this assignment necessary? This doesn't influence any test either?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, this was a different change from the PR's purpose...
This is not a change to simplify things, but to eliminate unnecessary processing.
Should I split the PR?
Details:
Here, if n_scale
is not 0
, the value of quot
is something like 0.000
.
We can safely remove trailing zeros from bc_num
here too, because early return returns a copy of BCG(_zero_)
regardless of the scale
value.
If do not set the n_scale
to 0
here, in the case of the Number
class, subsequent calculations will require extra calculations to be performed due to the unnecessary 0
.
(Either way, the result is the same: it's a matter of speed.)
edit:
This also applies to multiplication and round
, so it may be better to separate them into separate PRs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay I understand. Better in separate PR, that's cleaner and easier to keep an overview of why changes are done in which PR 🙂
Co-authored-by: Niels Dossche <[email protected]>
Thanks for your review!
I had completely forgotten about fuzzing, so I tested it. using: #18036 Additionally, using a technique similar to the fuzz above, we ran a test that generated values in PHP and compared the results with those in 8.3 for 4 million loops. All the outputs matched. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any clear mistakes.
While writing the code to make the
bc_num
struct hold the data asBC_VECTOR*
instead of achar*
, I realized that the code forbc_divide()
could be significantly simplified.Unfortunately, I won't use the structure change because it slows things down, but I'll try to simplify the code.
As you know, the code was too complicated and I didn't know where the bug was, so simplifying the code is a good thing.
benchmarks
When comparing the speed with the master, it is slightly faster.
1.php:
2.php:
3.php:
results 1:
results 2:
results 3: